#include "stollenApp.h"

//--------------------------------------------------------------
void stollenApp::setup(){

	camWidth 		= 320;	// try to grab at this size. 
	camHeight 		= 240;

	vidGrabber.setVerbose(true);
	vidGrabber.setDeviceID(0);
	vidGrabber.setDesiredFrameRate(60);
	vidGrabber.initGrabber(camWidth,camHeight);

	videoTexture.allocate(camWidth,camHeight, GL_RGB);	
	ofSetVerticalSync(true);

	//SOUND
	ofSetCircleResolution(80);
	ofBackground(54, 54, 54);	

	// 0 output channels, 
	// 2 input channels
	// 44100 samples per second
	// 256 samples per buffer
	// 4 num buffers (latency)

	soundStream.listDevices();

	//if you want to set a different device id 
	//soundStream.setDeviceID(0); //bear in mind the device id corresponds to all audio devices, including  input-only and output-only devices.

	int bufferSize = 256;


	left.assign(bufferSize, 0.0);
	right.assign(bufferSize, 0.0);
	volHistory.assign(400, 0.0);

	bufferCounter	= 0;
	drawCounter		= 0;
	smoothedVol     = 0.0;
	scaledVol		= 0.0;
	scaledVolMax	= 0.0;
	soundStream.setup(this, 0, 2, 44100, bufferSize, 4);
	buttonThread.countDown = "Push the Button!";
	buttonThread.doImage = false;
	buttonThread.buttonPushed = false;
	buttonThread.buildBon = false;
	buttonThread.doSoundCapture = false;

	//bon
	if(!bon1.loadImage("template/kassenzettel1.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon3.loadImage("template/kassenzettel3.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon4_1.loadImage("template/kassenzettel4_1.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon4_2.loadImage("template/kassenzettel4_2.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon4_3.loadImage("template/kassenzettel4_3.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon4_4.loadImage("template/kassenzettel4_4.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon4_5.loadImage("template/kassenzettel4_5.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon4_6.loadImage("template/kassenzettel4_6.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon4_7.loadImage("template/kassenzettel4_7.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon4_8.loadImage("template/kassenzettel4_8.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon4_9.loadImage("template/kassenzettel4_9.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon4_10.loadImage("template/kassenzettel4_10.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon5.loadImage("template/kassenzettel5.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon6_1.loadImage("template/kassenzettel6_1.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon6_2.loadImage("template/kassenzettel6_2.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}
	if(!bon7.loadImage("template/kassenzettel7.jpg")){
		ofLog(OF_LOG_ERROR, "Error while loading image");
	}

	//soundoutput
	buttonThread.beep1.loadSound("sounds/BEEP1.WAV");
	buttonThread.beep1.setVolume(1.00f);

	buttonThread.beep2.loadSound("sounds/BEEP2.WAV");
	buttonThread.beep2.setVolume(1.00f);

	printThread.beeping.loadSound("sounds/beeping.mp3");
	printThread.beeping.setVolume(1.00f);
}

//--------------------------------------------------------------
void stollenApp::update(){

	ofBackground(100,100,100);

	vidGrabber.update();
	vidGrabber.grabFrame();

/*	if(thread.doImage){
		saveImage();
		thread.doImage = false;
		videoTexture.loadData(vidGrabber.getPixels(), camWidth,camHeight, GL_RGB);
	}*/

	//SOUND
	//lets scale the vol up to a 0-1 range 
	scaledVol = ofMap(smoothedVol, 0.0, 0.17, 0.0, 1.0, true); //scaledVol = ofMap(smoothedVol, 0.0, 0.17, 0.0, 1.0, true);

	//save maximum volume
	if(buttonThread.doSoundCapture && scaledVol > scaledVolMax){
		scaledVolMax = scaledVol;
		keepImage();
	}

	//lets record the volume into an array
	volHistory.push_back( scaledVol );

	//if we are bigger the size we want to record - lets drop the oldest value
	if( volHistory.size() >= 400 ){
		volHistory.erase(volHistory.begin(), volHistory.begin()+1);
	}

	if(buttonThread.buildBon){
		buttonThread.buildBon = false;
		buildBon();
	}

	// update the sound playing system:
	ofSoundUpdate();
}

//--------------------------------------------------------------
void stollenApp::draw(){
	ofSetHexColor(0xffffff);
	vidGrabber.draw(20,20);
	videoTexture.draw(120+camWidth,20,camWidth,camHeight);

	//SOUND
	ofSetColor(225);
	//ofDrawBitmapString("AUDIO INPUT EXAMPLE", 32, 32);
	//ofDrawBitmapString("press 's' to unpause the audio\n'e' to pause the audio", 31, 92);

	ofNoFill();

	ofPushStyle();
	ofPushMatrix();
	ofTranslate(20, 270, 0);

	ofSetColor(225);
	ofDrawBitmapString("Scaled average vol (0-100): " + ofToString(scaledVol * 100.0, 0), 4, 18);

	ofDrawBitmapString("Countdown: " + buttonThread.countDown, 100+camWidth, 18);
	ofDrawBitmapString("Maximum vol (0-100): " + ofToString(scaledVolMax * 100.0, 0), 100+camWidth, 38);

	ofRect(0, 0, 400, 400);

	ofSetColor(245, 58, 135);
	ofFill();		
	ofCircle(200, 200, scaledVol * 190.0f);

	//lets draw the volume history as a graph
	ofBeginShape();
	for (int i = 0; i < volHistory.size(); i++){
		if( i == 0 ) ofVertex(i, 400);

		ofVertex(i, 400 - volHistory[i] * 70);

		if( i == volHistory.size() -1 ) ofVertex(i, 400);
	}
	ofEndShape(false);		

	ofPopMatrix();
	ofPopStyle();

	drawCounter++;

	ofSetColor(225);
	string reportString = "buffers received: "+ofToString(bufferCounter)+"\ndraw routines called: "+ofToString(drawCounter)+"\nticks: " + ofToString(soundStream.getTickCount());
	ofDrawBitmapString(reportString, 32, 589);
}

//--------------------------------------------------------------
void stollenApp::audioIn(float * input, int bufferSize, int nChannels){	

	float curVol = 0.0;

	// samples are "interleaved"
	int numCounted = 0;	

	//lets go through each sample and calculate the root mean square which is a rough way to calculate volume	
	for (int i = 0; i < bufferSize; i++){
		left[i]		= input[i*2]*0.5;
		right[i]	= input[i*2+1]*0.5;

		curVol += left[i] * left[i];
		curVol += right[i] * right[i];
		numCounted+=2;
	}

	//this is how we get the mean of rms :) 
	curVol /= (float)numCounted;

	// this is how we get the root of rms :) 
	curVol = sqrt( curVol );

	smoothedVol *= 0.93;
	smoothedVol += 0.07 * curVol;

	bufferCounter++;

}

void stollenApp::masterButtonPushed(){
	// start the thread
	buttonThread.buttonPushed = true;
	scaledVolMax = 0.0;
	buttonThread.startThread(false, false);    // blocking, non verbose
}

void stollenApp::keepImage(){
	videoTexture.loadData(vidGrabber.getPixels(), camWidth,camHeight, GL_RGB);  
	camImage.setFromPixels(vidGrabber.getPixels(), 320, 240, OF_IMAGE_COLOR);
}

void stollenApp::buildBon(){

	//templateImage.setFromPixels(vidGrabber.getPixels(), 320, 240, OF_IMAGE_COLOR);

	if(scaledVolMax>=0.0 && scaledVolMax<=0.1) bon4 = bon4_1;
	else if(scaledVolMax>0.1 && scaledVolMax<0.2) bon4 = bon4_2;
	else if(scaledVolMax>0.2 && scaledVolMax<0.3) bon4 = bon4_3;
	else if(scaledVolMax>0.3 && scaledVolMax<0.4) bon4 = bon4_4;
	else if(scaledVolMax>0.4 && scaledVolMax<0.5) bon4 = bon4_5;
	else if(scaledVolMax>0.5 && scaledVolMax<0.6) bon4 = bon4_6;
	else if(scaledVolMax>0.6 && scaledVolMax<0.7) bon4 = bon4_7;
	else if(scaledVolMax>0.7 && scaledVolMax<0.8) bon4 = bon4_8;
	else if(scaledVolMax>0.8 && scaledVolMax<0.9) bon4 = bon4_9;
	else if(scaledVolMax>0.9 && scaledVolMax<=1) bon4 = bon4_10;

	if(scaledVolMax<0.5) bon6 = bon6_1;
	else bon6 = bon6_2;
	
	bonWidth = bon1.getWidth();
	camImage.resize(bonWidth, bonWidth*240/320);

	bon1Height = bon1.getHeight();
	bon2Height = camImage.getHeight();
	bon3Height = bon3.getHeight();
	bon4Height = bon4_1.getHeight();
	bon5Height = bon5.getHeight();
	bon6Height = bon6_1.getHeight();
	bon7Height = bon7.getHeight();

	bonHeight = bon1Height+bon2Height+bon3Height+bon4Height+bon5Height+bon6Height+bon7Height;

	finalImage.allocate(bonWidth, bonHeight, OF_IMAGE_COLOR);

	/*for(int i=0; i<bonWidth; ++i){
		for(int j=0; j<bonHeight; ++j){
			finalImage.setColor(i,j,ofColor(255,0,0));
		}
	}*/

	for(int i=0; i<bonWidth; ++i){
		for(int j=0; j<bon1Height; ++j){
			finalImage.setColor(i,j,bon1.getColor(i,j));
		}
		for(int j=bon1Height; j<bon1Height+bon2Height; ++j){
			finalImage.setColor(i,j,camImage.getColor(i,j-bon1Height));
		}
		for(int j=bon1Height+bon2Height; j<bon1Height+bon2Height+bon3Height; ++j){
			finalImage.setColor(i,j,bon3.getColor(i,j-bon1Height-bon2Height));
		}
		for(int j=bon1Height+bon2Height+bon3Height; j<bon1Height+bon2Height+bon3Height+bon4Height; ++j){
			finalImage.setColor(i,j,bon4.getColor(i,j-bon1Height-bon2Height-bon3Height));
		}
		for(int j=bon1Height+bon2Height+bon3Height+bon4Height; j<bon1Height+bon2Height+bon3Height+bon4Height+bon5Height; ++j){
			finalImage.setColor(i,j,bon5.getColor(i,j-bon1Height-bon2Height-bon3Height-bon4Height));
		}
		for(int j=bon1Height+bon2Height+bon3Height+bon4Height+bon5Height; j<bon1Height+bon2Height+bon3Height+bon4Height+bon5Height+bon6Height; ++j){
			finalImage.setColor(i,j,bon6.getColor(i,j-bon1Height-bon2Height-bon3Height-bon4Height-bon5Height));
		}
		for(int j=bon1Height+bon2Height+bon3Height+bon4Height+bon5Height+bon6Height; j<bon1Height+bon2Height+bon3Height+bon4Height+bon5Height+bon6Height+bon7Height; ++j){
			finalImage.setColor(i,j,bon7.getColor(i,j-bon1Height-bon2Height-bon3Height-bon4Height-bon5Height-bon6Height));
		}
	}

	string path = "/results";
	ofDirectory dir(path);
	if(!dir.exists()){
		dir.create(true);
	}
	std::string absPath = dir.getAbsolutePath();
	std::string absPathPrint = absPath;

	//std::cout << absPathPrint << std::endl;

	std::string time = ofToString(ofGetUnixTime(), 0);
	finalImage.saveImage(absPath+"/Rosine_"+time+".jpg");
	printThread.path = absPathPrint+"\\Rosine_"+time+".jpg";
	printThread.startThread();
}

void stollenApp::replaceAll(std::string& str, const std::string& from, const std::string& to) {
    if(from.empty())
        return;
    size_t start_pos = 0;
    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
        str.replace(start_pos, from.length(), to);
        start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
    }
}


//--------------------------------------------------------------
void stollenApp::keyPressed  (int key){ 

	// in fullscreen mode, on a pc at least, the 
	// first time video settings the come up
	// they come up *under* the fullscreen window
	// use alt-tab to navigate to the settings
	// window. we are working on a fix for this...

	// Video settings no longer works in 10.7
	// You'll need to compile with the 10.6 SDK for this
	// For Xcode 4.4 and greater, see this forum post on instructions on installing the SDK
	// http://forum.openframeworks.cc/index.php?topic=10343        
	if (key == 's' || key == 'S'){
		vidGrabber.videoSettings();
	}

	/*	if (key == 'p' || key == 'P'){
	std::cout << "Snapshot taken" << std::endl;

	vidGrabber.grabFrame();    
	image.setFromPixels(vidGrabber.getPixels(), 320, 240, OF_IMAGE_COLOR);  
	image.saveImage("Tomtestimg.jpg");

	}*/

	/*if( key == 'q' ){
		soundStream.start();
	}

	if( key == 'w' ){
		soundStream.stop();
	}*/

	if( key == 'a' && !buttonThread.buttonPushed){
		masterButtonPushed();
	}
}

//--------------------------------------------------------------
void stollenApp::keyReleased(int key){ 

}

//--------------------------------------------------------------
void stollenApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void stollenApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void stollenApp::mousePressed(int x, int y, int button){
	if(!buttonThread.buttonPushed)
		masterButtonPushed();
}

//--------------------------------------------------------------
void stollenApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void stollenApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void stollenApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void stollenApp::dragEvent(ofDragInfo dragInfo){ 

}
